package com.szly.phm.admin.aspectj;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.szly.phm.admin.aspectj.annotation.OperationLogAnnotation;
import com.szly.phm.admin.async.LogAsync;
import com.szly.phm.admin.utils.IPUtils;
import com.szly.phm.admin.utils.SecurityUtils;
import com.szly.phm.common.entity.po.SysLog;
import com.szly.phm.common.utils.HandleUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private LogAsync logAsync;

    // 配置织入点
    @Pointcut("@annotation(com.szly.phm.admin.aspectj.annotation.OperationLogAnnotation)")
    public void logPointCut() {
    }

    /**
     * 请求处理完后执行
     *
     * @auther: chengjiang
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        handleLog(joinPoint, null, jsonResult);
    }

    /**
     * 请求出现异常时执行
     *
     * @auther: chengjiang
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    /**
     * 处理日志
     *
     * @auther: chengjiang
     */
    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
        try {
            // 获得注解
            OperationLogAnnotation controllerLog = getAnnotationLog(joinPoint);
            // 无注解直接return
            if (controllerLog == null) {
                return;
            }
            // 获取当前用户
            var loginUser = SecurityUtils.getLoginUser();
            var log = new SysLog();
            log.setId(HandleUtils.UUID32());
            log.setCreator(loginUser.getUsername());
            log.setCreateDateTime(new Date());
            log.setIpAddress(IPUtils.getRemoteAddr(request));
            log.setIsSoftDelete(false);
            log.setRemarks(request.getRequestURI());
            log.setOldData(JSONObject.toJSONString(jsonResult));
            // 处理注解上的参数
            this.getControllerMethodDescription(joinPoint, controllerLog, log);
            // 保存数据库
            logAsync.addOperationLog(log);
        } catch (Exception exp) {
            exp.printStackTrace();
        }
    }

    /**
     * 获取注解的相应属性
     *
     * @auther: chengjiang
     */
    public void getControllerMethodDescription(JoinPoint joinPoint, OperationLogAnnotation log, SysLog operationLog) throws Exception {
        // 获取模块名称
        var moduleName = log.getModuleName().getMessage();
        operationLog.setModuleName(moduleName);
        // 获取操作行为比如：增加修改等
        var action = log.getOperationAction().getMessage();
        operationLog.setLogType(action);
        // 获取接口参数内容
        this.setRequestValue(joinPoint, operationLog);

    }

    /**
     * 获取参数内容
     *
     * @auther: chengjiang
     */
    private void setRequestValue(JoinPoint joinPoint, SysLog operationLog) throws Exception {
        var requestMethod = request.getMethod();
        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
            var params = argsArrayToString(joinPoint.getArgs());
            operationLog.setNewData(StringUtils.substring(params, 0, 3000));
        } else {
            Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
            operationLog.setNewData(StringUtils.substring(paramsMap.toString(), 0, 2000));
        }
    }

    /**
     * 参数拼接
     *
     * @auther: chengjiang
     */
    private String argsArrayToString(Object[] paramsArray) {
        var params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if (!isFilterObject(paramsArray[i])) {
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
                    params += jsonObj.toString() + " ";
                }
            }
        }
        return params.trim();
    }

    /**
     * 过滤的对象。
     *
     * @param object 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    public boolean isFilterObject(final Object object) {
        return object instanceof MultipartFile || object instanceof HttpServletRequest || object instanceof HttpServletResponse;
    }

    /**
     * 否存在注解，如果存在就获取
     *
     * @auther: chengjiang
     */
    private OperationLogAnnotation getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(OperationLogAnnotation.class);
        }
        return null;
    }
}
